/*
 * Copyright (c) 2016. 石头哥哥
 */

package com.suweia.common.suweiredis.core;
/*

                  写字楼里写字间，写字间里程序员；
                  程序人'猿'写程序，又拿程序换酒钱。
                  酒醒只在网上坐，酒醉还来网下眠；
                  酒醉酒醒日复日，网上网下年复年。
                  但愿老死电脑间，不愿鞠躬老板前；
                  奔驰宝马贵者趣，公交自行程序员。
                  别人笑我忒疯癫，我笑自己命太贱；
                  不见满街漂亮妹，哪个归得程序'猿'？
━━━━━━神兽出没━━━━━━
 ┏┓   ┏┓
┏┛┻━━━┛┻┓
┃       ┃
┃   ━   ┃
┃ ┳┛ ┗┳ ┃
┃       ┃
┃   ┻   ┃
┃       ┃
┗━┓   ┏━┛
  ┃   ┃                    神兽保佑, 永无BUG!
  ┃   ┃       Code is far away from bug with the animal protecting
  ┃   ┗━━━┓
  ┃       ┣┓
  ┃       ┏┛
  ┗┓┓┏━┳┓┏┛
   ┃┫┫ ┃┫┫
   ┗┻┛ ┗┻┛
 */

import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Tuple;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import redis.clients.jedis.params.sortedset.ZAddParams;
import redis.clients.jedis.params.sortedset.ZIncrByParams;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Created by 石头哥哥 on 11/12/15.
 * <p>
 * server-service
 * <p>
 * com.suweia.intellibox.server_service.common.redis
 * <p>
 * comments:   redis  操作接口    速位定制接口
 */
public interface ISuWeiService {

    /**
     * 用于存储 pb
     *
     * @param key
     * @param value
     * @return Status code reply
     */
    String suwei_set(String key, byte[] value);

    /**
     * @param key
     * @return
     */
    byte[] suwei_get(String key);


    /**
     * 存储对象 ,  设置超时
     * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1
     * GB).
     *
     * @param key
     * @param value
     * @param time  expire time in the units of <code>expx</code>
     * @return Status code reply
     */
    String suwei_set(final String key, final byte[] value,
                     final long time);

    /**
     * 存储对象 ,  设置超时
     * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1
     * GB).
     *
     * @param key
     * @param value
     * @param nxxx  NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key
     *              if it already exist.
     * @param expx  EX|PX, expire time units: EX = seconds; PX = milliseconds   default is ex
     * @param time  expire time in the units of <code>expx</code>
     * @return Status code reply
     */
    String suwei_set(final byte[] key, final byte[] value, final byte[] nxxx, final byte[] expx,
                     final long time);


    /**
     * 添加set 集合
     *
     * @param key
     * @param value
     * @return
     */
    Long suwei_sadd(String key, byte[] value);

    /**
     * 获取 字节数组
     *
     * @param key
     * @return
     */
    Set<byte[]> suwei_smembers(String key);


    /**
     * set 集合中删除 某个元素
     * Remove the specified member from the set value stored at key. If member was not a member of the
     * set no operation is performed. If key does not hold a set value an error is returned.
     * <p>
     * Time complexity O(1)
     *
     * @param key     the key of the set
     * @param members the set member to remove
     * @return Integer reply, specifically: 1 if the new element was removed 0 if the new element was
     * not a member of the set
     */
    Long srem(final String key, final String... members);


    /**
     * @param key
     * @param value
     * @return
     */
    Long suwei_srem(final String key, final byte[]... value);

    /**
     * 添加一个元素到set集合中
     * Add the specified member to the set value stored at key. If member is already a member of the
     * set no operation is performed. If key does not exist a new set with the specified member as
     * sole member is created. If the key exists but does not hold a set value an error is returned.
     * <p>
     * Time complexity O(1)
     *
     * @param key
     * @param members
     * @return Integer reply, specifically: 1 if the new element was added 0 if the element was
     * already a member of the set
     */
    Long sadd(final String key, final String... members);


    /**
     * 添加到队列尾部
     *
     * @param key
     * @param value
     * @return 返回当前队列中的元素个数
     */
    Long suwei_rpush(String key, byte[] value);

    /**
     * @param key
     * @return 返回当前队列中的元素个数
     */
    Long suwei_llen(String key);

    /**
     * @param key
     * @param start 0
     * @param end   -1  获取所有元素
     * @return 返回元素list
     */
    List<byte[]> suwei_lrange(final String key, final long start, final long end);


    /**
     * 删除 start ---end之外的元素
     *
     * @param key
     * @param start
     * @param end
     * @return status code  ok?!
     */
    String suwei_ltrim(final String key, final long start, final long end);


    /**
     * @param key
     * @return
     */
    Set<String> smembers(String key);


    /**
     * @param key
     * @param member
     * @return
     */
    Boolean sismember(String key, String member);


    /**
     * Set the string value as value of the key.
     * The string can't be longer than 1073741824 bytes (1
     * GB).
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @param value
     * @return Status code reply
     */
    String set(String key, String value);

    /**
     * Set the string value as value of the key.
     * The string can't be longer than 1073741824 bytes (1
     * GB).
     *
     * @param key
     * @param value
     * @param nxxx  NX|XX, NX -- Only set the key if it does not already exist.
     *              XX -- Only set the key
     *              if it already exist.
     * @param expx  EX|PX, expire time units: EX = seconds; PX = milliseconds
     * @param time  expire time in the units of {@param #expx}
     * @return Status code reply
     */
    String set(String key, String value, String nxxx, String expx, long time);


    /**
     * Get the value of the specified key. If the key does not exist null is returned. If the value
     * stored at key is not a string an error is returned because GET can only handle string values.
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @return Bulk reply
     */
    String get(String key);

    /**
     * Test if the specified key exists. The command returns "1" if the key exists, otherwise "0" is
     * returned. Note that even keys set with an empty string as value will return "1". Time
     * complexity: O(1)
     *
     * @param key
     * @return Boolean reply, true if the key exists, otherwise false
     */
    Boolean exists(String key);

    /**
     * Return the type of the value stored at key in form of a string. The type can be one of "none",
     * "string", "list", "set". "none" is returned if the key does not exist. Time complexity: O(1)
     *
     * @param key
     * @return Status code reply, specifically: "none" if the key does not exist "string" if the key
     * contains a String value "list" if the key contains a List value "set" if the key
     * contains a Set value "zset" if the key contains a Sorted Set value "hash" if the key
     * contains a Hash value
     */
    String type(String key);

    /**
     * Set a timeout on the specified key. After the timeout the key will be automatically deleted by
     * the server. A key with an associated timeout is said to be volatile in Redis terminology.
     * <p>
     * Voltile keys are stored on disk like the other keys, the timeout is persistent too like all the
     * other aspects of the dataset. Saving a dataset containing expires and stopping the server does
     * not stop the flow of time as Redis stores on disk the time when the key will no longer be
     * available as Unix time, and not the remaining seconds.
     * <p>
     * Since Redis 2.1.3 you can update the value of the timeout of a key already having an expire
     * set. It is also possible to undo the expire at all turning the key into a normal key using the
     * {@link #persist(String) PERSIST} command.
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @param seconds
     * @return Integer reply, specifically: 1: the timeout was set. 0: the timeout was not set since
     * the key already has an associated timeout (this may happen only in Redis versions <
     * 2.1.3, Redis >= 2.1.3 will happily update the timeout), or the key does not exist.
     * @see <ahref="http://code.google.com/p/redis/wiki/ExpireCommand">ExpireCommand</a>
     */
    Long expire(String key, int seconds);

    /**
     * Undo a {@link #expire(String, int) expire} at turning the expire key into a normal key.
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @return Integer reply, specifically: 1: the key is now persist. 0: the key is not persist (only
     * happens when key not set).
     */
    Long persist(String key);


    /**
     * EXPIREAT works exctly like {@link #expire(String, int) EXPIRE} but instead to get the number of
     * seconds representing the Time To Live of the key as a second argument (that is a relative way
     * of specifing the TTL), it takes an absolute one in the form of a UNIX timestamp (Number of
     * seconds elapsed since 1 Gen 1970).
     * <p>
     * EXPIREAT was introduced in order to implement the Append Only File persistence mode so that
     * EXPIRE commands are automatically translated into EXPIREAT commands for the append only file.
     * Of course EXPIREAT can also used by programmers that need a way to simply specify that a given
     * key should expire at a given time in the future.
     * <p>
     * Since Redis 2.1.3 you can update the value of the timeout of a key already having an expire
     * set. It is also possible to undo the expire at all turning the key into a normal key using the
     * {@link #persist(String) PERSIST} command.
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @param unixTime
     * @return Integer reply, specifically: 1: the timeout was set. 0: the timeout was not set since
     * the key already has an associated timeout (this may happen only in Redis versions <
     * 2.1.3, Redis >= 2.1.3 will happily update the timeout), or the key does not exist.
     * @see <ahref="http://code.google.com/p/redis/wiki/ExpireCommand">ExpireCommand</a>
     */
    Long expireAt(String key, long unixTime);

    /**
     * time life
     * <p>
     * The TTL command returns the remaining time to live in seconds of a key that has an
     * {@link #expire(String, int) EXPIRE} set. This introspection capability allows a Redis client to
     * check how many seconds a given key will continue to be part of the dataset.
     *
     * @param key
     * @return Integer reply, returns the remaining time to live in seconds of a key that has an
     * EXPIRE. In Redis 2.6 or older, if the Key does not exists or does not have an
     * associated expire, -1 is returned. In Redis 2.8 or newer, if the Key does not have an
     * associated expire, -1 is returned or if the Key does not exists, -2 is returned.
     */
    Long ttl(String key);


//    Boolean setbit(String key, long offset, boolean value);
//
//    Boolean setbit(String key, long offset, String value);
//
//    Boolean getbit(String key, long offset);


//    Long setrange(String key, long offset, String value);
//
//    String getrange(String key, long startOffset, long endOffset);
//
//    String getSet(String key, String value);

    /**
     * SETNX actually means "SET if Not eXists".
     *
     * @param key
     * @param value
     * @return
     */
    Long setnx(String key, String value);

    /**
     * The command is exactly equivalent to the following group of commands:
     * {@link #set(String, String) SET} + {@link #expire(String, int) EXPIRE}. The operation is
     * atomic.
     * <p>
     * Time complexity: O(1)
     *
     * @param key
     * @param seconds
     * @param value
     * @return Status code reply
     */
    String setex(String key, int seconds, String value);


    /**
     * @param key
     * @param integer
     * @return
     */
    Long decrBy(String key, long integer);

    /**
     * @param key
     * @return
     */
    Long decr(String key);

    /**
     * @param key
     * @param integer
     * @return
     */
    Long incrBy(String key, long integer);

    /**
     * @param key
     * @return
     */
    Long incr(String key);

    /**
     * If the key already exists and is a string, this command appends the provided value at the end
     * of the string. If the key does not exist it is created and set as an empty string, so APPEND
     * will be very similar to SET in this special case.
     * <p>
     * Time complexity: O(1). The amortized time complexity is O(1) assuming the appended value is
     * small and the already present value is of any size, since the dynamic string library used by
     * Redis will double the free space available on every reallocation.
     *
     * @param key
     * @param value
     * @return Integer reply, specifically the total length of the string after the append operation.
     */
    Long append(String key, String value);

    /**
     * @param key
     * @param start
     * @param end
     * @return
     */
    String substr(String key, int start, int end);

    /**
     * cache object attr
     * hash cache
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    Long hset(String key, String field, String value);

    /**
     * get filed value
     *
     * @param key
     * @param field
     * @return
     */
    String hget(String key, String field);

    /**
     * Set the specified hash field to the specified value if the field not exists. <b>Time
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    Long hsetnx(String key, String field, String value);

    /**
     * Set the respective fields to the respective values. HMSET replaces old values with new values.
     * <p>
     * If key does not exist, a new key holding a hash is created.
     * <p>
     * <b>Time complexity:</b> O(N) (with N being the number of fields)
     *
     * @param key
     * @param hash file and value
     * @return Return OK or Exception if hash is empty
     */
    String hmset(String key, Map<String, String> hash);

    /**
     * get filed value
     *
     * @param key
     * @param fields
     * @return
     */
    List<String> hmget(String key, String... fields);

    /**
     * @param key
     * @param field
     * @param value
     * @return
     */
    Long hincrBy(String key, String field, long value);

    /**
     * @param key
     * @param field
     * @return
     */
    Boolean hexists(String key, String field);

    /**
     * delete filed
     *
     * @param key
     * @param field
     * @return
     */
    Long hdel(String key, String... field);

    /**
     * @param key
     * @return
     */
    Long hlen(String key);

    /**
     * if has key ,will return >0
     *
     * @param key
     * @return
     */
    Long del(String key);

    /**
     * if has key ,will return >0
     *
     * @param keys
     * @return
     */
    Long del(String... keys);

    /**
     * Return all the fields in a hash.
     *
     * @param key
     * @return
     */
    Set<String> hfields(String key);

    /**
     * Return all the values in a hash.
     *
     * @param key
     * @return
     */
    List<String> hvals(String key);

    /**
     * Return all the fields and associated values in a hash.
     *
     * @param key
     * @return
     */
    Map<String, String> hgetAll(String key);


    void zadd(final String key, final double score, final String member);

    void zadd(final String key, final double score, final String member,
              final ZAddParams params);

    void zadd(final String key, final Map<String, Double> scoreMembers);

    void zadd(final String key, final Map<String, Double> scoreMembers, final ZAddParams params);


    void zrem(final String key, final String... members);


    /**
     * 升序删除 指定区间元素
     *
     * @param key
     * @param start
     * @param end
     */
    long zremrange(final String key, final long start, final long end);


    /**
     * 倒序删除指定区间元素
     *
     * @param key
     * @param start
     * @param end
     */
    long zrevremrange(final String key, final long start, final long end);

    void zincrby(final String key, final double score, final String member);

    void zincrby(final String key, final double score, final String member,
                 final ZIncrByParams params);

    long zrank(final String key, final String member);

    long zrevrank(final String key, final String member);

    Set<String> zrange(final String key, final long start, final long end);


    Set<String> zrevrange(final String key, final long start, final long end);

    Set<Tuple> zrangeWithScores(final String key, final long start, final long end);

    Set<Tuple> zrevrangeWithScores(final String key, final long start, final long end);

    long zcard(final String key);

    double zscore(final String key, final String member);

    //   geo command

    /**
     * 添加地理信息
     *
     * @param key       位置key
     * @param longitude 经度
     * @param latitude  纬度
     * @param member    位置名称
     * @return add status
     */
    Long geoadd(String key, double longitude, double latitude, String member);

    /**
     * 添加地理信息
     *
     * @param key
     * @param memberCoordinateMap key is :地理名称 , GeoCoordinate value: 坐标信息(jedis封装经纬度)
     * @return add status
     */
    Long geoadd(String key, Map<String, GeoCoordinate> memberCoordinateMap);

    /**
     * 查询指定位置直接的距离
     *
     * @param key     位置信息key
     * @param member1 成员1   (key)
     * @param member2 成员2    (key)
     * @return 返回距离
     */
    Double geodist(String key, String member1, String member2);

    /**
     * 查询指定位置直接的距离
     *
     * @param key     位置信息key
     * @param member1 成员1   (key)
     * @param member2 成员2    (key)
     * @param unit    {GeoUnit.KM}   距离单位
     * @return
     */
    Double geodist(String key, String member1, String member2, GeoUnit unit);

    /**
     * 查询位置GEOHASH编码
     *
     * @param key
     * @param members
     * @return
     */
    List<String> geohash(String key, String... members);

    /**
     * 查询指定位置的 坐标信息 (经纬度)
     *
     * @param key
     * @param members
     * @return
     */
    List<GeoCoordinate> geopos(String key, String... members);

    /**
     * 查询指定经纬度位置 ----指定半径范围内的 具体对象位置信息
     *
     * @param key       位置key
     * @param longitude 经度
     * @param latitude  纬度
     * @param radius    半径
     * @param unit      单位 KM ,M
     * @return
     */
    List<GeoRadiusResponse> georadius(String key, double longitude, double latitude, double radius, GeoUnit unit);

    /**
     * 根据经纬度
     * <p>
     * 查询指定经纬度位置 ----指定半径范围内的 具体对象位置信息
     *
     * @param key       位置key
     * @param longitude 经度
     * @param latitude  纬度
     * @param radius    半径
     * @param unit      单位 KM ,M
     * @param param     {@link GeoRadiusParam} 对于查询数据排序方式或者count 等
     * @return 指定位置(半径内) 地理信息数据
     */
    List<GeoRadiusResponse> georadius(String key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param);

    /**
     * 根据地理位名称来查找----指定半径范围内的 具体对象位置信息
     *
     * @param key    位置key
     * @param member 地理名称
     * @param radius 半径
     * @param unit   单位 KM ,M
     * @return 指定位置(半径内) 地理信息数据
     */
    List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius, GeoUnit unit);

    /**
     * 根据地理位名称来查找----指定半径范围内的 具体对象位置信息
     *
     * @param key    位置key
     * @param member 地理名称
     * @param radius 半径
     * @param unit   单位 KM ,M
     * @param param  {@link GeoRadiusParam} 对于查询数据排序方式或者count 等
     * @return 指定位置(半径内) 地理信息数据
     */
    List<GeoRadiusResponse> georadiusByMember(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param);


}
